/**
 * @file    portserial.c
 * @brief   FreeModbus UART串口移植层实现
 * @details 本文件实现了FreeModbus协议栈在STM32平台上的UART串口通信功能，
 *          包括串口初始化、数据收发、中断处理等核心功能。
 */

#include "mb.h"             /* FreeModbus核心头文件 */
#include "mbport.h"         /* FreeModbus移植层接口头文件 */
#include "port_internal.h"  /* 内部移植层定义头文件 */

UART_HandleTypeDef uart_mb;  /* FreeModbus使用的UART句柄 */ 

/**
 * @note STM32处理器的UART配置与标准配置存在差异
 * 
 * 参考链接：https://community.st.com/t5/stm32-mcus-products/uart-parity-and-data-bit-issue-in-stm32c0-series/td-p/713896
 *
 * 标准配置 8E1 (8数据位+偶校验+1停止位):
 * - 其他处理器: WordLength = 8, Parity = EVEN
 * - STM32配置: WordLength = 9 (8数据位+校验位), Parity = EVEN
 *
 * 标准配置 7E1 (7数据位+偶校验+1停止位):
 * - 其他处理器: WordLength = 7, Parity = EVEN  
 * - STM32配置: WordLength = 8 (7数据位+校验位), Parity = EVEN
 *
 * @warning STM32的WordLength包含了校验位，需要根据实际数据位数和校验设置进行调整
 */


/**
 * @brief 初始化Modbus串口通信
 * @details 根据指定参数配置UART外设，支持不同的波特率、数据位、校验位和停止位配置。
 *          该函数处理STM32特有的UART配置方式，自动调整WordLength以适配校验位设置。
 * 
 * @param ucPORT 串口端口号（当前实现中未使用，保留用于多串口扩展）
 * @param ulBaudRate 波特率，常用值：9600, 19200, 38400, 57600, 115200
 * @param ucDataBits 数据位数，支持8位和9位
 * @param eParity 校验方式：MB_PAR_NONE(无校验), MB_PAR_ODD(奇校验), MB_PAR_EVEN(偶校验)
 * @param ucStopBits 停止位数：UART_STOPBITS_1 或 UART_STOPBITS_2
 * 
 * @return BOOL 初始化结果
 */
BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity, UCHAR ucStopBits)
{
    UNUSED( ucPORT );  /* 端口号参数未使用，保留用于多串口支持 */

    /* 配置UART基本参数 */
    uart_mb.Instance          = MB_USART;              /* UART外设实例 */
    uart_mb.Init.BaudRate     = ulBaudRate;            /* 设置波特率 */
    uart_mb.Init.StopBits     = ucStopBits;            /* 设置停止位数 */
    uart_mb.Init.Mode         = UART_MODE_TX_RX;       /* 启用发送和接收模式 */
    uart_mb.Init.HwFlowCtl    = UART_HWCONTROL_NONE;   /* 禁用硬件流控 */
    uart_mb.Init.OverSampling = UART_OVERSAMPLING_16;  /* 16倍过采样，提高抗干扰能力 */

    /* 根据数据位数和校验方式配置字长和校验参数 */
    if( ucDataBits == 8 )
    {
        if( eParity == MB_PAR_NONE )
        {
            /* 8位数据，无校验 */
            uart_mb.Init.WordLength = UART_WORDLENGTH_8B;
            uart_mb.Init.Parity     = UART_PARITY_NONE;
        }
        else
        {
            /* 8位数据，有校验：STM32需要设置为9位字长（8数据位+1校验位） */
            uart_mb.Init.WordLength = UART_WORDLENGTH_9B;
            uart_mb.Init.Parity     = (eParity == MB_PAR_ODD) ? UART_PARITY_ODD : UART_PARITY_EVEN;
        }
    }
    else if( ucDataBits == 9 )
    {
        if( eParity == MB_PAR_NONE )
        {
            /* 9位数据，无校验 */
            uart_mb.Init.WordLength = UART_WORDLENGTH_9B;
            uart_mb.Init.Parity     = UART_PARITY_NONE;
        }
        else
        {
            /* 9位数据配置有校验位时不支持（总共需要10位） */
            return FALSE;
        }
    }
    else
    {
        /* 不支持的数据位配置 */
        return FALSE;
    }

    /* 初始化UART外设 */
    if( HAL_UART_Init( &uart_mb ) != HAL_OK )
    {
        return FALSE;  /* UART硬件初始化失败 */
    }

    /* 初始状态下禁用接收和发送中断，避免意外触发 */
    __HAL_UART_DISABLE_IT(&uart_mb, UART_IT_RXNE);  /* 禁用接收中断 */
    __HAL_UART_DISABLE_IT(&uart_mb, UART_IT_TXE);   /* 禁用发送中断 */

    return TRUE;  /* 初始化成功 */
}

/**
 * @brief 初始化Modbus UART硬件资源
 * @details 配置UART时钟、GPIO引脚和中断优先级，在xMBPortSerialInit()之前调用
 */
void MB_Uart_Init(void)
{
    /* 使能UART外设时钟，为UART工作提供时钟源 */
    MB_USART_CLK_ENABLE();

    /* 初始化串口TX和RX引脚 */
    MB_TX_GPIO_Init();  /* 初始化发送引脚 */
    MB_RX_GPIO_Init();  /* 初始化接收引脚 */

    /* 如果使用RS485，初始化RS485控制引脚 */
    #if (MB_USE_RS485 == 1)
    MB_RS485_RE_GPIO_CLK_ENABLE();  /* 使能RS485控制引脚GPIO时钟 */
    MB_RS485_RE_GPIO_Init();        /* 初始化RS485控制引脚 */
    #endif

    /* 配置NVIC中断控制器 */
    HAL_NVIC_SetPriority(MB_USART_IRQn, MB_USART_IRQ_priority, MB_USART_IRQ_subpriority);
    HAL_NVIC_DisableIRQ(MB_USART_IRQn);  /* 初始状态禁用中断，等待后续启用 */
}

/**
 * @brief 启用或禁用Modbus串口的接收和发送功能
 * @details 控制UART的接收和发送中断，实现通信方向控制
 * @param rxEnable 接收功能控制：TRUE=启用，FALSE=禁用
 * @param txEnable 发送功能控制：TRUE=启用，FALSE=禁用
 */
void vMBPortSerialEnable(BOOL rxEnable, BOOL txEnable)
{
    /* 配置期间临时禁用NVIC中断，确保配置过程的原子性 */
    HAL_NVIC_DisableIRQ(MB_USART_IRQn);
        
    /* 配置接收中断 */
    if (rxEnable)
    {
        __HAL_UART_ENABLE_IT(&uart_mb, UART_IT_RXNE);   /* 启用接收非空中断 */
        /* 如果使用RS485，切换到接收模式 */
        #if (MB_USE_RS485 == 1)
        MB_RS485_RE(0);  /* 切换到接收模式 */
        #endif
    }
    else
    {
        __HAL_UART_DISABLE_IT(&uart_mb, UART_IT_RXNE);  /* 禁用接收非空中断 */
    }
    
    /* 配置发送中断 */
    if (txEnable)
    {
        __HAL_UART_ENABLE_IT(&uart_mb, UART_IT_TXE);    /* 启用发送空中断 */
        /* 如果使用RS485，切换到发送模式 */
        #if (MB_USE_RS485 == 1)
        MB_RS485_RE(1);  /* 切换到发送模式 */
        #endif
    }
    else
    {
        __HAL_UART_DISABLE_IT(&uart_mb, UART_IT_TXE);   /* 禁用发送空中断 */
    }
    
    /* 仅当至少有一个方向启用时才重新启用NVIC中断 */
    if( rxEnable || txEnable )
    {
        HAL_NVIC_EnableIRQ(MB_USART_IRQn);  /* 重新启用UART中断 */
    }
    /* 如果两个方向都禁用，则保持NVIC中断禁用状态，节省CPU资源 */
}

/**
 * @brief 通过Modbus串口发送单个字节
 * @details 使用HAL库阻塞式发送，超时时间1ms
 * @param byte 要发送的字节数据
 * @return BOOL 发送结果：TRUE=成功，FALSE=失败
 */
BOOL xMBPortSerialPutByte(CHAR byte)
{
    /* 使用HAL库阻塞式发送单个字节，超时时间1ms */
    if(HAL_UART_Transmit(&uart_mb, (uint8_t *)&byte, 1, 0x01) != HAL_OK)
    {
        return FALSE;  /* 发送失败（超时或硬件错误） */
    }
    else
    {
        return TRUE;   /* 发送成功 */
    }
}

/**
 * @brief 从Modbus串口接收单个字节
 * @details 使用HAL库阻塞式接收，超时时间1ms
 * @param byte 指向接收数据缓冲区的指针
 * @return BOOL 接收结果：TRUE=成功，FALSE=失败
 */
BOOL xMBPortSerialGetByte(CHAR *byte)
{
    /* 使用HAL库阻塞式接收单个字节，超时时间1ms */
    if(HAL_UART_Receive(&uart_mb, (uint8_t *)byte, 1, 0x01) != HAL_OK)
    {
        return FALSE;  /* 接收失败（超时或硬件错误） */
    }
    else
    {
        return TRUE;   /* 接收成功 */
    }
}

/**
 * @brief Modbus UART中断服务程序
 * @details 处理UART接收和发送中断，转换为FreeModbus协议栈回调
 */
void MB_USART_IRQHandler(void)
{
    /* 检查并处理接收非空中断 */
    if(__HAL_UART_GET_IT_SOURCE(&uart_mb, UART_IT_RXNE) != RESET)
    {
        vMBTimerDebugSetLow();        /* 调试信号控制，用于时序分析 */
        pxMBFrameCBByteReceived();    /* 通知FreeModbus协议栈有字节接收 */
    }

    /* 检查并处理发送空中断 */
    if(__HAL_UART_GET_IT_SOURCE(&uart_mb, UART_IT_TXE) != RESET)
    {
        pxMBFrameCBTransmitterEmpty(); /* 通知FreeModbus协议栈发送缓冲区空闲 */
    }

    /* 清除NVIC中的挂起中断标志，防止重复触发 */
    HAL_NVIC_ClearPendingIRQ(MB_USART_IRQn);
    
    /* 调用HAL库的通用UART中断处理函数，处理其他可能的中断源 */
    HAL_UART_IRQHandler(&uart_mb);
}
